---
title: "Null, Undefined and Option"
description: "JS interop with nullable and optional values in ReScript"
canonical: "/docs/manual/null-undefined-option"
section: "Language Features"
order: 11
---

# Null, Undefined and Option

ReScript itself doesn't have the notion of `null` or `undefined`. This is a _great_ thing, as it wipes out an entire category of bugs. No more `undefined is not a function`, and `cannot access someAttribute of undefined`!

However, the **concept** of a potentially nonexistent value is still useful, and safely exists in our language.

We represent the existence and nonexistence of a value by wrapping it with the `option` type. Here's its definition from the standard library:

<CodeTab labels={["ReScript", "JS Output"]}>

```res example
type option<'a> = None | Some('a)
```

```js
// Empty output
```

</CodeTab>

It means "a value of type option is either None (representing nothing) or that actual value wrapped in a Some".

**Note** how the `option` type is just a regular [variant](./variant.mdx).

## Example

Here's a normal value:

<CodeTab labels={["ReScript", "JS Output"]}>

```res example
let licenseNumber = 5
```

```js
var licenseNumber = 5;
```

</CodeTab>

To represent the concept of "maybe null", you'd turn this into an `option` type by wrapping it. For the sake of a more illustrative example, we'll put a condition around it:

<CodeTab labels={["ReScript", "JS Output"]}>

```res
let licenseNumber =
  if personHasACar {
    Some(5)
  } else {
    None
  }
```

```js
var licenseNumber = personHasACar ? 5 : undefined;
```

</CodeTab>

Later on, when another piece of code receives such value, it'd be forced to handle both cases through [pattern matching](./pattern-matching-destructuring.mdx):

<CodeTab labels={["ReScript", "JS Output"]}>

```res
switch licenseNumber {
| None =>
  Console.log("The person doesn't have a car")
| Some(number) =>
  Console.log("The person's license number is " ++ Int.toString(number))
}
```

```js
var number = licenseNumber;

if (number !== undefined) {
  console.log("The person's license number is " + number.toString());
} else {
  console.log("The person doesn't have a car");
}
```

</CodeTab>

By turning your ordinary number into an `option` type, and by forcing you to handle the `None` case, the language effectively removed the possibility for you to mishandle, or forget to handle, a conceptual `null` value! **A pure ReScript program doesn't have null errors**.

## Interoperate with JavaScript `undefined` and `null`

The `option` type is common enough that we special-case it when compiling to JavaScript:

<CodeTab labels={["ReScript", "JS Output"]}>

```res example
let x = Some(5)
```

```js
var x = 5;
```

</CodeTab>

simply compiles down to `5`, and

<CodeTab labels={["ReScript", "JS Output"]}>

```res example
let x = None
```

```js
var x;
```

</CodeTab>

compiles to `undefined`! If you've got e.g. a string in JavaScript that you know might be `undefined`, type it as `option<string>` and you're done! Likewise, you can send a `Some(5)` or `None` to the JS side and expect it to be interpreted correctly =)

### Caveat 1

Unfortunately, lots of times, your JavaScript value might be _both_ `null` or `undefined`. In that case, you unfortunately can't type such value as e.g. `option<int>`, since our `option` type only checks for `undefined` and not `null` when dealing with a `None`.

#### Solution: More Sophisticated `undefined` & `null` Interop

To solve this, we provide access to more elaborate `null` and `undefined` helpers through the [`Nullable`](/docs/manual/api/stdlib/nullable) module. This somewhat works like an `option` type, but is different from it.

#### Examples

To create a JS `null`, use the value `Nullable.null`. To create a JS `undefined`, use `Nullable.undefined` (you can naturally use `None` too, but that's not the point here; the `Nullable.*` helpers wouldn't work with it).

If you're receiving, for example, a JS string that can be `null` and `undefined`, type it as:

<CodeTab labels={["ReScript", "JS Output"]}>

```res example
@module("MyConstant") external myId: Nullable.t<string> = "myId"
```

```js
// Empty output
```

</CodeTab>

To create such a nullable string from our side (presumably to pass it to the JS side, for interop purpose), do:

<CodeTab labels={["ReScript", "JS Output"]}>

```res example
@module("MyIdValidator") external validate: Nullable.t<string> => bool = "validate"
let personId: Nullable.t<string> = Nullable.make("abc123")

let result = validate(personId)
```

```js
var MyIdValidator = require("MyIdValidator");
var personId = "abc123";
var result = MyIdValidator.validate(personId);
```

</CodeTab>

The `return` part "wraps" a string into a nullable string, to make the type system understand and track the fact that, as you pass this value around, it's not just a string, but a string that can be `null` or `undefined`.

#### Convert to/from `option`

`Nullable.fromOption` converts from a `option` to `Nullable.t`. `Nullable.toOption` does the opposite.
